package club.emergency.wechat.aliyun_sms.provider.impl;

import club.emergency.wechat.aliyun_sms.SendMessage;
import club.emergency.wechat.aliyun_sms.provider.properties.SendMessageProperties;
import club.emergency.wechat.common.response.StatusCode;
import club.emergency.wechat.common.response.ResponseEntity;
import club.emergency.wechat.redis.RedisOperation;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.google.gson.Gson;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Create with IntelliJ IDEA
 * Project Name: wechat
 * Package Name: club.emergency.wechat.aliyun_sms.provider.impl
 * Date: 2018/11/13
 *
 * @author: 快乐的小菌菌
 * Description: 短信API产品的DEMO程序,工程中包含了一个SmsDemo类，直接通过执行main函数即可体验短信产品API功能(只需要将AK替换成开通了云通信-短信产品功能的AK即可)国际短信发送请勿参照此DEMO
 * <p>"{code:" + generateCode() + "}"
 * 作为公众模块开发，sendSms方法注入SmsProperties对象，不同模块引用该模块实现短信验证的时候自己根据不同的用户权限和短信模板CODE自行开发
 */
@RestController
public class SendMessageImpl implements SendMessage {

    /**
     * 固定不变
     */
    private static final String PRODUCT = "Dysmsapi";
    /**
     * 固定不变
     */
    private static final String DOMAIN = "dysmsapi.aliyuncs.com";


    private SendMessageProperties sendMessageProperties;

    private RedisOperation<String> redisOperation;

    public SendMessageImpl(SendMessageProperties sendMessageProperties, RedisOperation<String> redisOperation) {
        this.sendMessageProperties = sendMessageProperties;
        this.redisOperation = redisOperation;
    }

    @Override
    public String sendSms(@RequestParam("phoneNumber") String phoneNumber, @RequestBody Map<String, Object> paramMap) {

        SendSmsResponse sendSmsResponse = null;

        //初始化acsClient,暂不支持region化（请勿修改）
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", sendMessageProperties.getAccessKeyId(), sendMessageProperties.getAccessKeySecret());
        try {
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", PRODUCT, DOMAIN);
            IAcsClient acsClient = new DefaultAcsClient(profile);

            //组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();
            //必填:待发送手机号
            request.setPhoneNumbers(phoneNumber);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName("北京泽雯科技有限公司");
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(sendMessageProperties.getTemplateCode());
            //可选:模板中的变量替换JSON串,如模板内容为"您的验证码为${code}"时,此处的值为json格式
            request.setTemplateParam(new Gson().toJson(paramMap));
            //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
            request.setOutId(null);

            //hint 此处可能会抛出异常，注意catch
            sendSmsResponse = acsClient.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            return ResponseEntity.error(StatusCode.SEND_SMS_ERROR, "短信发送失败", sendSmsResponse);
        }
        return ResponseEntity.ok(StatusCode.SEND_SMS_OK, "短信发送成功", sendSmsResponse);
    }

    @Override
    public String sendVerificationSms(@RequestParam("phoneNumber") String phoneNumber) {
        String code = generateCode();
        redisOperation.add("sms_" + phoneNumber, code, 5, TimeUnit.MINUTES);
        Map<String, Object> map = new HashMap<>(1);
        map.put("code", code);
        String sendSmsStr = sendSms(phoneNumber, map);
        ResponseEntity responseEntity = new Gson().fromJson(sendSmsStr, ResponseEntity.class);
        if (responseEntity.getStatusCode() == StatusCode.SEND_SMS_OK) {
            return ResponseEntity.ok(StatusCode.SEND_SMS_OK, "短信发送成功", null);
        }
        return ResponseEntity.error(StatusCode.SEND_SMS_ERROR, "短信验证码发送失败", null);
    }

    @Override
    public String confirmVerification(@RequestParam("phoneNumber") String phoneNumber, @RequestParam("confirmCode") String confirmCode) {
        String key = "sms_" + phoneNumber;
        Boolean flag = redisOperation.hasKey(key);
        if (Objects.isNull(flag) || !flag) {
            return ResponseEntity.error(StatusCode.CONFIRM_VERIFICATION_EXPIRE, "验证码已失效，请重新验证手机验证码！", null);
        }
        String code = redisOperation.get(key, String.class);
        if (Objects.nonNull(code)) {
            if (code.equals(confirmCode)) {
                //验证码只能用一次
                redisOperation.delete(key);
                return ResponseEntity.ok(StatusCode.CONFIRM_VERIFICATION_OK, "短信验证码验证成功", null);
            }
        }
        return ResponseEntity.error(StatusCode.CONFIRM_VERIFICATION_ERROR, "短信验证失败", null);
    }


    /**
     * 6位随机数生成
     *
     * @return 6位数字字符串
     */
    private String generateCode() {
        int randNum = 1 + (int) (Math.random() * ((999999 - 1) + 1));
        return String.valueOf(randNum);
    }

}
